#ifndef MAGIC_H_INCLUDED
#define MAGIC_H_INCLUDED

#include "common.h"
#include "Creature.h"
#include "Tile.h"
#include "Motion.h"
#include <iostream>
#include <list>
using std::cerr;
using std::list;

class Magic
{
public:
    Magic();
    virtual ~Magic() ;

    virtual void draw(BITMAP *surface) = 0;
    static void Draw(BITMAP *surface);

private:
    static list<Magic *> m_magics;
};

class MagicTimer;

class DurationMagic : public Magic
{
    static const int LIFE_INFINITE = 0x0fffffff;
public:
    DurationMagic(MagicTimer *timer, int interval, int lifetime = LIFE_INFINITE);
    ~DurationMagic();

    inline void setLifeTime(int lifetime)
    {
        m_lifetime = lifetime;
    }
    inline bool valid()
    {
        if (m_lifetime <= 0)
            m_valid = false;
        return m_valid;
    }

    inline bool valid(bool flag)
    {
        m_valid = flag;
        return m_valid;
    }

    inline void decLifeTime()
    {
        if (m_lifetime == LIFE_INFINITE)
            return;

        --m_lifetime;
    }
    virtual void OnTimer() = 0;
private:
    int  m_lifetime;
    bool m_valid;
    MagicTimer *m_timer;
};

class MagicTimer
{
public:
    struct MagicStruct
    {
        MagicStruct(DurationMagic *m, int interval) : m_magic(m), m_interval(interval), m_lastTick(0) {}
        DurationMagic *m_magic;
        int            m_interval;
        int            m_lastTick;
    };
    typedef MagicTimer class_type;
    typedef list<MagicStruct> MAGIC_LIST;

    ~MagicTimer();
    void add(DurationMagic *m, int interval);
    void remove(DurationMagic *m);
    void OnTimer(int tick);
    inline size_t size() const
    {
        return m_magics.size();
    }


private:
    MAGIC_LIST m_magics;
};

class Motion;

class Missile : public DurationMagic
{
public:
    Missile(MagicTimer *timer, int interval, const Rect &r, Motion *m = NULL) : DurationMagic(timer, interval),  m_position(r) , m_motion(m) {}
    ~Missile() ;
    void setSpeed(ushort sx, ushort sy)
    {
        m_position.w = sx;
        m_position.h = sy;
    }
    void setMotion (Motion *m)
    {
        m_motion = m;
    }
    void OnTimer();
    Rect &getPosition()
    {
        return m_position;
    }

    virtual void OnStep() {}
    virtual void OnHitMonster() { valid(false); }
    virtual void OnHitPlace() { valid(false); }
    virtual void OnHitBlock() { valid(false); }
private:
    Rect     m_position;
    Motion  *m_motion;
};

class FireBolt : public Missile
{
public:
    FireBolt(MagicTimer *timer, int interval, const Rect & from, Motion *m) : Missile(timer, interval, from, m)
    {
        m_tile = INST(TileManager).getTile(3);
        setLifeTime(50);
    }
    ~FireBolt()
    {
//        cerr << __PRETTY_FUNCTION__ << "\n";
    }
    void draw(BITMAP *surface)
    {
        short sx, sy;
        Rect &m = getPosition();
        mapxy_to_screenxy(m.x, m.y, sx, sy);
        if (sx > 0 && sx < SCREEN_W && sy > 0 && sy < SCREEN_H) {
                draw_sprite(surface, m_tile, sx, sy);
        }
    }
private:
    BITMAP * m_tile;
};

class FireBall : public Missile
{
#define ANGLE  0.31415926
public:
    FireBall(MagicTimer *timer, int interval, const Rect & from, Motion *m) : Missile(timer, interval, from, m)
    {
//        setLifeTime(50);
        m_angle = ANGLE;
    }
    ~FireBall()
    {
        Rect p = getPosition();
        for (unsigned i = 0; i < 20; ++i)
        {
            p.w = (short)(10 * sin(ANGLE*i));
            p.h = (short)(10 * cos(ANGLE*i));
            m_angle += ANGLE;
            new FireBolt(&(INST(MagicTimer)), 1, p, new Motion);
        }
//        cerr << __PRETTY_FUNCTION__ << "\n";
    }
    void OnStep()
    {
        Rect p = getPosition();
        p.w = (short)(20 * sin(m_angle));
        p.h = (short)(20 * cos(m_angle));
        m_angle += ANGLE;
        new FireBolt(&(INST(MagicTimer)), 2, p, new Motion);
    }
    void draw(BITMAP *surface)
    {
    }
private:
    float    m_angle;
};

/*
class RangeDamage : public DurationMagic
{
};

class Enchance : public DurationMagic
{
};
*/

#endif // MAGIC_H_INCLUDED
